#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <iostream>
#include <vector>
#include <string.h>

typedef void (*callback_t)();
//#define WIFEXITED(status) (!(status&0x7F))
//#define WEXITSTATUS(status) ((status>>8)&0xFF)

enum 
{
    OK,
    USAGE_ERR 
};

void Task()
{
    int cnt = 5;
    while(cnt--)
    {
        std::cout << "我是子进程, 我正在完成Task任务" << std::endl;
        sleep(1);
    }
}

void Hello()
{
    int cnt = 5;
    while(cnt--)
    {
        std::cout << "我是子进程, 我正在完成hello任务" << std::endl;
        sleep(1);
    }
}

// 一般：
// 输入：const &
// 输出：*
// 输入输出：&
void CreateChildProcess(int num, std::vector<pid_t> *subs, const std::vector<callback_t> &cbs)
{
    for (int i = 0; i < num; i++)
    {
        pid_t id = fork();
        if (id == 0)
        {
            printf("我是子进程, pid:%d, ppid:%d\n", getpid(), getppid());
            cbs[i%2]();
            exit(OK);
        }
        subs->push_back(id);
    }

}

void WaitAllChild(const std::vector<pid_t> &subs)
{
    for (const auto &pid : subs)
    {
        int status = 0;
        pid_t rid = waitpid(pid, &status, 0);
        if (rid > 0)
        {
            printf("子进程:%d Exit, exit_code:%d\n", rid, WEXITSTATUS(status));
        }
    }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "Usage:" << argv[0] << " process_num" << std::endl;
        exit(USAGE_ERR);
    }
    
    int num = std::stoi(argv[1]);
    std::vector<pid_t> subs;
    // 不同的子进程执行不同的任务
    std::vector<callback_t> cbs;
    cbs.push_back(Task);
    cbs.push_back(Hello);
    // 创建多个子进程
    CreateChildProcess(num, &subs, cbs);
    // 等待进程
    WaitAllChild(subs);
}

//void PrintLog()
//{
//    std::cout << "Printf Log" << std::endl;    
//}
//
//void SyncDisk()
//{
//    std::cout << "Write Data To Disk" << std::endl;
//}
//
//void WriteDataToMysql()
//{
//    std::cout << "Write Data To Mysql" << std::endl;
//}

//int main()
//{
//    printf("我是父进程, pid:%d, ppid:%d\n", getpid(), getppid());
//    std::vector<callback_t> tasks;
//    tasks.push_back(PrintLog);
//    tasks.push_back(SyncDisk);
//    tasks.push_back(WriteDataToMysql);
//
//    pid_t id = fork();
//    
//    if (id < 0)
//    {
//        perror("fork");
//        exit(1);
//    }
//    else if (id == 0)
//    {//child
//        int cnt = 5;
//        while(cnt--)
//        {
//            printf("我是子进程, pid:%d, ppid:%d\n", getpid(), getppid());
//            sleep(1);
//        }
//        exit(0);
//    }
//    else
//    {//parent
//        //非阻塞轮询
//        while(1)
//        {
//            int status = 0;
//            pid_t rid = waitpid(id, &status, WNOHANG);
//            if (rid > 0)
//            {
//                if (WIFEXITED(status))
//                {
//                    printf("wait success!, 退出的子进程是:%d, exit_code:%d\n",\
//                            rid, WEXITSTATUS(status));
//                }
//                else 
//                {
//                    printf("子进程异常退出\n");
//                }
//                break;
//            }
//            else if (rid == 0)
//            {
//                printf("子进程还在运行, 父进程需要等待\n");
//                usleep(100000);
//                
//                for (auto &task : tasks)
//                    task();
//            }
//            else 
//            {
//                perror("waitpid");
//                break;
//            }
//        }
//
//        //阻塞
//        //int status = 0;
//        //pid_t rid = waitpid(id, &status, 0);
//        //if (rid > 0)
//        //{
//        //    if (WIFEXITED(status))
//        //    {
//        //        printf("wait success!, 退出的子进程是:%d, exit_code:%d\n",\
//        //                rid, WEXITSTATUS(status));
//        //    }
//        //    else 
//        //    {
//        //        printf("子进程异常退出\n");
//        //    }
//        //    //printf("wait success!, status:%d, exit_code:%d, exit_sig:%d\n",\
//        //    //        status, (status >> 8)& 0xFF, status & 0x7F);
//        //}
//        //else{
//        //    perror("waitpid");
//        //}
//    }
//}
